import copy
import glob
import os

# import trimesh
import json5
import numpy as np
from OCC.Core.BRep import BRep_Builder
from OCC.Core.BRep import BRep_Tool
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_MakeEdge, BRepBuilderAPI_MakeWire, BRepBuilderAPI_MakeFace
from OCC.Core.BRepBuilderAPI import BRepBuilderAPI_Transform
# from dopy.transform import vector_rotation_matrix
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeCone, BRepPrimAPI_MakeBox, BRepPrimAPI_MakeCylinder
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakePrism
from OCC.Core.TopLoc import TopLoc_Location
from OCC.Core.TopTools import (TopTools_IndexedMapOfShape)
from OCC.Core.TopoDS import TopoDS_Compound
from OCC.Core.TopoDS import TopoDS_Shape
from OCC.Core.TopoDS import (topods_Vertex,  # downcasting functions
                             )
from OCC.Core.gp import gp_Pnt, gp_Trsf, gp_Vec, gp_Dir
from OCC.Extend.DataExchange import read_step_file
from OCC.Extend.DataExchange import write_stl_file
from OCC.Extend.TopologyUtils import TopologyExplorer

# from fillet import Rounding,Chamfer
# from transformations import identity_matrix,transform_points,concatenate_matrices,rotation_matrix,translation_matrix
try:
    from features import Rounding,Chamfer,CylindricalHole,LinearForm
    from transformations import identity_matrix,transform_points,concatenate_matrices,rotation_matrix,translation_matrix
except:
    from .features import Rounding,Chamfer,CylindricalHole,LinearForm
    from .transformations import identity_matrix, transform_points, concatenate_matrices, rotation_matrix, \
        translation_matrix

import re

try:
    from .path_helper import direction,Line,Linear_solver,PathPrism,PrismBuilder
except:
    from path_helper import direction,Line,Linear_solver,PathPrism,PrismBuilder
_BASEDIR = os.path.dirname(os.path.abspath(__file__))

# GROUP_DIR = os.path.join(_BASEDIR, "./group/test")

class Global_Cache:
    Cache = {}
    PART_DIR=''
    GROUP_DIR=''


def get_Cache():
    for dirname in [Global_Cache.PART_DIR, Global_Cache.GROUP_DIR]:
        json_files = glob.glob(os.path.join(dirname, "*.json5"))
        for json_file in json_files:
            key = os.path.basename(json_file).split('.')[0]
            with open(json_file, "r", encoding="utf-8") as fp:
                obj = json5.load(fp)

            if dirname == Global_Cache.PART_DIR:
                Global_Cache.Cache[key] = obj
            else:
                Global_Cache.Cache['.' + key] = obj


# Cache = {}

class Part(object):
    AXIS_X = (np.array([0, 0, 0], dtype=float), np.array([1, 0, 0], dtype=float))
    AXIS_Y = (np.array([0, 0, 0], dtype=float), np.array([0, 1, 0], dtype=float))
    AXIS_Z = (np.array([0, 0, 0], dtype=float), np.array([0, 0, 1], dtype=float))

    def __init__(self, part_type, part_dir=Global_Cache.PART_DIR,use_json=False,extra_args=None, global_cache=None):
        self.use_json = use_json

        if global_cache is not None:
            Global_Cache.Cache = copy.deepcopy(global_cache)

        self.parse_element(part_type, part_dir)

        for name in self.elements:
            category = self.elements[name]['category']

            if category == '__box__':
                for k in ['x', 'y', 'z']:
                    k1 = name + '__' + k
                    if k1 not in self.args:
                        self.args[k1] = {}

                    if 'v' not in self.args[k1]:
                        self.args[k1]['v'] = 20

            elif category in ['__cylinder__', '__cone__']:
                for k in ['r', 'h']:
                    k1 = name + '__' + k
                    if k1 not in self.args:
                        self.args[k1] = {}

                    if 'v' not in self.args[k1]:
                        self.args[k1]['v'] = 20

            elif category =='__stp__':
                pass

        self.parse_extra_args(extra_args)
        self.construct()
        self.parse_step_file_txt()
        self.get_transform()

    def parse_extra_args(self, extra_args):
        if extra_args is None: return

        for ele in extra_args:
            name = ele['name']
            if name not in self.args:
                self.args[name] = {}

            self.args[name].update(ele)

    def parse_element_json(self,json):
        self.elements=json['elements']
        self.args=json['args']
        self.points = json['points']
        self.lines=json['lines']
        self.trans = json['trans']
        self.features = json['features']

    def parse_element(self, element_type, element_dir, prefix=''):
        if len(Global_Cache.Cache) == 0:
            get_Cache()
        self.element_type = element_type

        self.elements = {}
        self.args = {}
        self.points = {}
        self.lines={}
        self.trans = {}
        if self.use_json == False:
            if isinstance(element_type, dict):
                obj = element_type
            else:
                if prefix + element_type in Global_Cache.Cache:
                    obj = Global_Cache.Cache[prefix + element_type]
                else:
                    # warnings.warn(prefix + element_type + ' not in Cache')
                    with open(os.path.join(element_dir, element_type + ".json5"), "r", encoding="utf-8") as fp:
                        obj = json5.load(fp)

            # assert 'elements' in obj
            if 'trans' not in obj: obj['trans'] = {}
            if 'points' not in obj: obj['points'] = {}
            if 'args' not in obj: obj['args'] = {}
            if 'lines' not in obj:obj['lines']={}
            self.obj = obj

        elif self.use_json==True:
            self.obj = self.json

        for ele in self.obj['elements']:
            dic = {}
            for k in ['category', 'desc','address']:
                if k in ele:
                    dic[k] = ele[k]

            dic['transform'] = identity_matrix()
            if "features" in self.obj:
                dic=self.parse_features(dic,ele)
            self.elements[ele['name']] = dic

        for ele in self.obj['args']:
            dic = {}
            for k in ele:
                dic[k] = ele[k]

            self.args[ele['name']] = dic

        for ele in self.obj['points']:
            dic = {}
            for k in ['refer', 'offset']:
                if k in ele:
                    dic[k] = ele[k]

            self.points[ele['name']] = dic

        for ele in self.obj['lines']:
            dic = {}
            for k in ele:
                dic[k]=copy.deepcopy(ele[k])
            self.lines[ele['name']] = dic

        for i, ele in enumerate(self.obj['trans']):
            name = ele.get('name', str(i))
            dic = {}
            for k in ['group', 'point2point', 'rotate', 'move', 'align']:
                if k in ele:
                    dic[k] = copy.deepcopy(ele[k])

            self.trans[name] = dic

    def construct(self):
        vs = {}

        for k in self.args:
            vs[k] = self.args[k].get('v')

        for k in self.args:
            code = self.args[k].get('code')
            if code is not None:
                if isinstance(code,list):
                    for c in code:
                        exec(c.strip(),vs)
                else:
                    exec(code.strip(), vs)

        for k in self.args:
            self.args[k]['v'] = vs[k]

        for k1 in self.trans:
            for k2 in self.trans[k1]:
                if isinstance(self.trans[k1][k2], (list, tuple)):
                    for i in range(len(self.trans[k1][k2])):
                        if isinstance(self.trans[k1][k2][i], str):
                            s = self.trans[k1][k2][i]
                            if s.startswith('$'):
                                self.trans[k1][k2][i] = vs[s[1:]]

    def get_normal(self,name):
        if '.' in name:
            ss=name.split('.')

            element=self.elements[ss[0]]
            position = ss[1]
            if element['category']=='__stp__':
                try:
                    index=int(position)
                except:
                    index=position
                line_normal=self.cahce_normals[ss[0]+'.'+position]
                assert (line_normal is not None)
                line_normal=transform_points([np.array(line_normal)],element['transform'])[0]
                return line_normal
            else:
                raise NotImplementedError()
        else:
            assert name in self.lines
            refer = self.lines[name].get('refer')
            line_normal=self.get_normal(refer)
            return line_normal

    def get_point(self, name):
        if isinstance(name, list):
            assert len(name) == 3
            return np.array(name, dtype=float)

        if '.' in name:
            ss = name.split('.')
            assert len(ss) == 2

            element = self.elements[ss[0]]

            position = ss[1]

            if element['category'] == '__box__':
                point = np.array([0, 0, 0], dtype=float)
                vs = dict(
                    x=self.args[ss[0] + '__' + 'x']['v'],
                    y=self.args[ss[0] + '__' + 'y']['v'],
                    z=self.args[ss[0] + '__' + 'z']['v']
                )

                if '+x' in position:
                    point[0] = vs['x'] * 0.5
                elif '-x' in position:
                    point[0] = -vs['x'] * 0.5
                if '+y' in position:
                    point[1] = vs['y'] * 0.5
                elif '-y' in position:
                    point[1] = -vs['y'] * 0.5
                if '+z' in position:
                    point[2] = vs['z'] * 0.5
                elif '-z' in position:
                    point[2] = -vs['z'] * 0.5

                coor = transform_points([point], element['transform'])[0]

                return coor
            elif element['category'] in ['__cylinder__', '__cone__']:
                point = np.array([0, 0, 0], dtype=float)
                vs = dict(
                    r=self.args[ss[0] + '__' + 'r']['v'],
                    h=self.args[ss[0] + '__' + 'h']['v'],
                )

                if '+x' in position:
                    point[0] = vs['r']
                elif '-x' in position:
                    point[0] = -vs['r']
                if '+y' in position:
                    point[1] = vs['r']
                elif '-y' in position:
                    point[1] = -vs['r']
                if '+z' in position:
                    point[2] = vs['h'] * 0.5
                elif '-z' in position:
                    point[2] = -vs['h'] * 0.5

                coor = transform_points([point], element['transform'])[0]

                return coor

            elif element['category'] =='__stp__':
                try:
                    index=int(position)
                except:
                    index=position
                if not isinstance(index,str):
                    m = read_step_file(element["address"])
                    exp = TopologyExplorer(m)
                    shape_map = TopTools_IndexedMapOfShape()
                    for e in exp.vertices():
                        shape_map.Add(e)

                    vertex = topods_Vertex(shape_map.FindKey(int(position)))
                    # edge_face_map = TopTools_IndexedDataMapOfShapeListOfShape()
                    aPnt = BRep_Tool.Pnt(vertex)
                    coor = transform_points([np.array([aPnt.X(), aPnt.Y(), aPnt.Z()])], element['transform'])[0]
                else:
                    vertex=self.cache_points[ss[0]+'.'+position]
                    assert(vertex is not None)
                    coor=transform_points([np.array(vertex)],element['transform'])[0]
                return coor
                # coor = transform_points([point], element['transform'])[0]
            elif element['category'] == '__extrude__':
                position_index=int(position[2:])
                vertex_list=[]
                p0=np.array(self.args[name+"__p0x"]['v'],self.args[name+"__p0y"]['v'])
                vertex_list.append(p0)
                for i in range(1,int(self.args[ss[0]+"__vertex_num"]['v'])):
                    x=float(self.args[ss[0]+"__"+"p"+str(i)+"x"]['v'])
                    y=float(self.args[ss[0]+"__"+'p'+str(i)+"y"]['v'])
                    p=np.array([x,y])
                    vertex_list.append(p)
                vertex=None
                if '+' in position:
                    vertex=np.array([vertex_list[position_index][0],vertex_list[position_index][1],float(self.args[ss[0]+"__extrude"]['v'])])
                else:
                    vertex = np.array([vertex_list[position_index][0],vertex_list[position_index][1], 0])
                coor=transform_points([np.array(vertex)],element['transform'])[0]
                return coor
            else:
                raise NotImplementedError()
        else:
            assert name in self.points

            refer = self.points[name].get('refer')
            offset = self.points[name].get('offset')

            if refer is None:
                coor = np.array([0, 0, 0], np.float32)
            else:
                coor = self.get_point(refer)

            if offset is not None:
                coor += np.array(offset)

            return coor

    def add_transform(self, group, m):
        assert isinstance(group, list)

        for e in group:
            element = self.elements[e]
            element['transform'] = concatenate_matrices(
                m, element['transform'])

    def get_parameters(self):
        '''
        以“_”开头的变量为内部变量
        '''
        vs = {}
        for k in self.args:
            if not k.startswith('_') and not bool(self.args[k].get('isconst', False)):
                vs[k] = self.args[k]['v']

        return vs

    def get_transform(self):
        for ele in self.trans.values():
            if 'align' in ele:
                a0 = [
                    self.get_point(ele['align'][0] + '.+x'),
                    self.get_point(ele['align'][0] + '.+y'),
                    self.get_point(ele['align'][0] + '.+z')
                ]

                a1 = [
                    self.get_point(ele['align'][1] + '.+x'),
                    self.get_point(ele['align'][1] + '.+y'),
                    self.get_point(ele['align'][1] + '.+z')
                ]

                a0 = np.array(a0) - self.get_point(ele['align'][0] + '.o')
                a1 = np.array(a1) - self.get_point(ele['align'][1] + '.o')

                m = vector_rotation_matrix(a0, a1)
                self.add_transform(ele['group'], m)

            if 'rotate' in ele:
                if ele['rotate'][1][1:] in ['x','y','z']:
                    axis_map = {
                        "+x": Part.AXIS_X,
                        "+y": Part.AXIS_Y,
                        "+z": Part.AXIS_Z,
                    }
                    axis = axis_map[ele['rotate'][1].lower()]

                    m = rotation_matrix(
                        np.deg2rad(ele['rotate'][0]),
                        axis[1],
                        axis[0]
                    )
                else:
                    m=ele['rotate'][0]

                self.add_transform(ele['group'], m)

            if 'point2point' in ele:
                d1 = self.get_point(ele['point2point'][0])
                d2 = self.get_point(ele['point2point'][1])

                v = d2 - d1

                if len(ele['point2point']) >= 3:
                    keep = ele['point2point']
                    if 'x' not in keep:
                        v[0] = 0
                    if 'y' not in keep:
                        v[1] = 0
                    if 'z' not in keep:
                        v[2] = 0

                m = translation_matrix(v)

                self.add_transform(ele['group'], m)

            if 'move' in ele:
                m = translation_matrix(ele['move'])

                self.add_transform(ele['group'], m)


    def parse_features(self,dic,ele):
        dic['features'] = []
        for feature in self.obj["features"]:
            if feature["type"] == "rounding":

                for detail in feature["details"]:
                    if detail["element_name"] == ele["name"]:
                        dic['features'].append({"type": "rounding",
                                                "details": {}})
                        dic['features'][-1]['details']['edges_id']=detail['edges_id']
                        dic['features'][-1]['details']['radius']=detail['radius']

            elif feature["type"] == "chamfer":

                for detail in feature["details"]:
                    if detail["element_name"]==ele["name"]:
                        dic['features'].append({"type": "chamfer",
                                                "details": {}})
                        dic["features"][-1]["details"]["fillet"]=detail["fillet"]

            elif feature["type"] == "hole":
                for detail in feature["details"]:
                    if detail["element_name"]==ele["name"]:
                        dic['features'].append({"type":"hole",
                                                "details":{}})
                        dic["features"][-1]["details"]["hole_paras"]=detail["hole_paras"]

            elif feature["type"] == "groove":
                for detail in feature["details"]:
                    if detail["element_name"]==ele["name"]:
                        dic['features'].append({"type":"groove",
                                                "details":{}})
                        dic["features"][-1]["details"]["groove_paras"]=detail["groove_paras"]
        return dic


    def set_features(self,shape,features):
        if len(features)==0:
            return shape
        feature = features[0]
        if feature["type"] == "rounding":
            if len(feature["details"])==0:
                return shape
            else:
                R=Rounding(solid=shape,r=feature["details"]["radius"],index_list=feature["details"]['edges_id'])
                shape = R.filleted_shape()
                return self.set_features(shape,features[1:])

        elif feature["type"] == "chamfer":
            if len(feature["details"])==0:
                return shape
            else:
                C=Chamfer(solid=shape,chamfer_detail=feature["details"]['fillet'])
                shape = C.filleted_shape()
                return self.set_features(shape,features[1:])

        elif feature["type"] == "hole":
            if len(feature["details"])==0:
                return shape
            else:
                hole=feature["details"]["hole_paras"]
                point=gp_Pnt(hole["point"][0],hole["point"][1],hole["point"][2])
                direction=gp_Dir(hole["direction"][0],hole["direction"][1],hole["direction"][2])
                high=hole["high"]
                radius=hole["radius"]
                H=CylindricalHole(shape=shape,point=point,direction=direction,high=high,radius=radius)
                shape = H.make_hole()
                return self.set_features(shape,features[1:])

        elif feature["type"]=="groove":
            if len(feature["details"])==0:
                return shape
            else:
                groove=feature["details"]["groove_paras"]
                plane = groove["plane"]

                wire_points=groove["wire"]
                pt1=gp_Pnt(wire_points[0][0],wire_points[0][1],wire_points[0][2])
                pt2=gp_Pnt(wire_points[1][0],wire_points[1][1],wire_points[1][2])
                wire = BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(pt1,pt2).Edge()).Wire()

                move_directions = groove["move_directions"]
                operations_num = groove["operations_num"]
                L=LinearForm(shape,plane, wire,move_directions, operations_num)
                shape = L.make_features()
                return self.set_features(shape,features[1:])



    def shape(self, debug=False):
        mesh_all = None
        for name in self.elements:

            category = self.elements[name]['category']
            if category == '__box__':
                element = self.elements[name]
                x, y, z = (
                    self.args[name + '__' + 'x']['v'],
                    self.args[name + '__' + 'y']['v'],
                    self.args[name + '__' + 'z']['v']
                )
                m = BRepPrimAPI_MakeBox(gp_Pnt(-x/2,-y/2,-z/2),x, y, z).Shape()
                if "features" in self.obj:
                    feature = self.elements[name]["features"]
                    m=self.set_features(m,feature)

            elif category in ['__cylinder__', '__cone__']:
                element = self.elements[name]
                rh = [
                    self.args[name + '__' + 'r']['v'],
                    self.args[name + '__' + 'h']['v'],
                ]
                if category == '__cylinder__':
                    Cylinder = BRepPrimAPI_MakeCylinder(
                        rh[0],
                        rh[1]
                    ).Shape()
                    m = TopoDS_Shape(Cylinder)
                    T = gp_Trsf()
                    T.SetTranslation(gp_Vec(0, 0, -rh[1]/2))
                    loc = TopLoc_Location(T)
                    m.Location(loc)

                else:

                    Cone = BRepPrimAPI_MakeCone(
                        rh[0],
                        0,
                        rh[1],
                    ).Shape()
                    m = TopoDS_Shape(Cone)
                    T = gp_Trsf()
                    T.SetTranslation(gp_Vec(0, 0, -rh[1]/2))
                    loc = TopLoc_Location(T)
                    m.Location(loc)
            elif category=='__stp__':
                element = self.elements[name]
                m = read_step_file(self.elements[name]["address"])

            elif category=='__path__':
                element = self.elements[name]
                path = self.args[name+'__'+'path']['v']

                x, y = (
                    self.args[name + '__' + 'x']['v'],
                    self.args[name + '__' + 'y']['v'],
                )


                if len(path)>1:
                    Ps = PathPrism(path,dx=x,dy=y)
                    Ps.init()
                    cycles = Ps.cycle()
                    #print(type(cycles))
                    # print(Ps.unit_normal)
                    for i in range(len(cycles)):
                        cycles[i]=cycles[i]-Ps.unit_normal*y/2
                    PB = PrismBuilder(cycles,Ps.unit_normal,y)

                    prism=PB.build_prism()

                elif len(path)==1:

                    continue

                m=prism

            # elif category=='__path__':
            #     element = self.elements[name]
            #     path = self.args[name+'__'+'path']['v']
            #
            #     x, y = (
            #         self.args[name + '__' + 'x']['v'],
            #         self.args[name + '__' + 'y']['v'],
            #     )
            #
            #     if len(path)>1:
            #         edge_0 = np.array(path[0])
            #         edge_1 = np.array(path[1])
            #         paths = []
            #         dirs = []
            #         unit_verticals=[]
            #         positive_points=[]
            #         negative_points=[]
            #         dir0 = edge_0[1] - edge_0[0]
            #         dir1 = edge_1[1] - edge_1[0]
            #         normal = np.cross(dir0,dir1)
            #         unit_normal = normal/np.linalg.norm(normal)
            #         for i in range(len(path)):
            #             path_=np.array(path[i])
            #             paths.append(path_)
            #             dir=paths[i][1]-paths[i][0]
            #             dirs.append(dir)
            #             unit_dir = dir/np.linalg.norm(dir)
            #             unit_vertical = np.cross(unit_normal,unit_dir)
            #             unit_verticals.append(unit_vertical)
            #             positive_points.append(path_[0]+unit_vertical*x/2)
            #             negative_points.append(path_[0]-unit_vertical*x/2)
            #             if i == len(path)-1:
            #                 positive_points.append(path_[1]+unit_vertical*x/2)
            #                 negative_points.append(path_[1]-unit_vertical*x/2)
            #
            #         unit_dir0 = dir0/np.linalg.norm(dir0)
            #         unit_vertical = np.cross(unit_normal,unit_dir0)
            #
            #
            #
            #
            #         start_point=edge_0[0]+unit_vertical*x/2
            #         end_point=edge_0[0]-unit_vertical*x/2
            #
            #
            #     elif len(path)==1:
            #         continue
            #     mkw = BRepBuilderAPI_MakeWire()
            #     mkw.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(0., 0., 0.), gp_Pnt(x, 0., 0.)).Edge())
            #     mkw.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(x, 0, 0.), gp_Pnt(x, y, 0.)).Edge())
            #     mkw.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(x, y, 0.), gp_Pnt(0., y, 0.)).Edge())
            #     mkw.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(0., y, 0.), gp_Pnt(0., 0., 0.)).Edge())
            #
            #     # from OCC.Display.SimpleGui import init_display
            #     # display, start_display, add_menu, add_function_to_menu = init_display("wx")
            #     #
            #     #
            #     # display.DisplayShape(BRepBuilderAPI_MakeFace(mkw.Wire()).Face(), update=True)
            #     # start_display()
            #     face=BRepBuilderAPI_MakeFace(mkw.Wire()).Face()
            #     cross_section=self.args[name+'__'+'cross_section']['v']
            #     pieces=[]
            #     for i in range(len(path)):
            #         # mkw1 = BRepBuilderAPI_MakeWire()
            #         # mkw1.Add(BRepBuilderAPI_MakeEdge(gp_Pnt(cross_section[i][])).Edge())
            #         pieces.append(BRepPrimAPI_MakePrism(face,
            #                               gp_Vec(gp_Pnt(path[i][0][0], path[i][0][1], path[i][0][2]),
            #                                      gp_Pnt(path[i][1][0], path[i][1][1], path[i][1][2]))).Shape())
            #
            #         # my_face = BRepBuilderAPI_MakeFace(mkw.Wire()).Face()
            #         # face = TopoDS_Shape(my_face)
            #         T1 = gp_Trsf()
            #         # T = gp_Ax1(gp_Pnt(0, 1, 0), gp_Dir(0, 6, 4))
            #         # T1.SetRotation(T, 1)
            #         T1.SetTranslation(gp_Vec(path[i][1][0]-path[i][0][0], path[i][1][1]-path[i][0][1], path[i][1][2]-path[i][0][2]))
            #         # if i>=1:
            #         #     dir0 = direction(path[i-1])
            #         #     dir1 = direction(path[i])
            #         #     if np.inner(dir0,dir1) == 0:
            #         #         axis = np.cross(dir0,dir1)
            #         #         point = gp_Pnt(0,0,0)
            #         #         T = gp_Ax1(point,gp_Dir(axis[0], axis[1], axis[2]))
            #         #         T1.SetRotation(T,pi/2)
            #         #T1.SetScale(gp_Pnt(path[i][0][0], path[i][0][1], path[i][0][2]),2)
            #         coneLoc = TopLoc_Location(T1)
            #         face.Move(coneLoc)
            #
            #     myNewShape = pieces
            #     compound = TopoDS_Compound()
            #     B = BRep_Builder()
            #     B.MakeCompound(compound)
            #     for shape in myNewShape:
            #         B.Add(compound, shape)
            #     m=compound

            elif category=='__extrude__':
                element=self.elements[name]
                vertex_list=[]
                p0=np.array([float(self.args[name+"__p0x"]['v']),float(self.args[name+"__p0y"]['v'])])
                vertex_list.append(p0)
                for i in range(1,int(self.args[name+"__vertex_num"]['v'])):
                    x=float(self.args[name+"__"+"p"+str(i)+"x"]['v'])
                    y=float(self.args[name+"__"+"p"+str(i)+"y"]['v'])
                    p=np.array([x,y])
                    vertex_list.append(p)
                vertex_list.append(p0)
                W1=BRepBuilderAPI_MakeWire()

                for i in range(1,int(self.args[name+"__vertex_num"]['v']+1)):
                    p1=gp_Pnt(float(vertex_list[i - 1][0]), float(vertex_list[i - 1][1]), 0.)
                    p2=gp_Pnt(float(vertex_list[i][0]), float(vertex_list[i][1]), 0.)
                    e=BRepBuilderAPI_MakeEdge(p1,p2).Edge()
                    W1.Add(e)
                extrude=float(self.args[name+"__extrude"]['v'])
                prism = BRepPrimAPI_MakePrism(BRepBuilderAPI_MakeFace(W1.Wire()).Face(), gp_Vec(0., 0, extrude)).Shape()
                m = TopoDS_Shape(prism)
            else:
                raise NotImplementedError()


            a = [[element['transform'][i][j] for j in range(4)] for i in range(3)]

            T = gp_Trsf()
            myshape = TopoDS_Shape(m)
            T.SetValues(a[0][0], a[0][1], a[0][2], a[0][3],
                        a[1][0], a[1][1], a[1][2], a[1][3],
                        a[2][0], a[2][1], a[2][2], a[2][3])
            trans = BRepBuilderAPI_Transform(T)
            trans.Perform(myshape)
            new_shape = trans.Shape()

            if mesh_all is None:
                mesh_all = [new_shape]
            else:
                mesh_all.append(new_shape)

        return mesh_all

    def compound(self):
        myNewShape=self.shape()
        compound = TopoDS_Compound()
        B = BRep_Builder()
        B.MakeCompound(compound)
        for shape in myNewShape:
            B.Add(compound, shape)

        return compound

    def show(self, points=None, radius=5):
        pass

    def to_stl(self,save_dir,filename):
        # make sure the path exists otherwise OCE get confused
        if not os.path.isdir(save_dir):
            raise AssertionError("wrong path provided")
        stl_file = os.path.join(save_dir, filename)
        write_stl_file(self.shape(), stl_file)

    def parse_step_file_txt(self):
        self.cache_points={}
        self.cahce_normals={}
        pointpattern = re.compile(r'AP-\d{2}-[AB]-\d{2}')
        linepattern = re.compile(r'NL-\d{2}')
        for k,v in self.elements.items():
            element=v
            if element['category'] =='__stp__':
                f = open(element["address"], 'r')
                # datas=f.read()
                datalines = f.readlines()
                f.close()
                f = open(element["address"], 'r')
                datas=f.read()
                vertex_list = pointpattern.findall(datas)
                nl_list = linepattern.findall(datas)
                f.close()
                datalines = [line for line in datalines if line[0] == '#']

                line_dict={}
                for line in datalines:
                    gg=line.split('=')
                    line_dict[gg[0]]=gg[1]
                for v1 in vertex_list:
                    linecode=[data for data in datalines if 'CARTESIAN_POINT' in data and v1 in data]
                    assert len(linecode)>0
                    data=linecode[0]
                    line_corr = data.split("(")[1:]
                    coor = line_corr[1].split(')')[0]
                    coordinate = coor.split(',')[0:]
                    coordinate = [float(s) for s in coordinate]
                    self.cache_points[k+'.'+v1]= np.array(coordinate)
                codepattern = re.compile(r'#\d+')
                for l1 in nl_list:
                    linecode = [line for line in datalines if l1 in line]
                    assert len(linecode) > 0
                    line_corr = linecode[0].split("(")[1:]
                    lineid = line_corr[1].split(')')[0]
                    line_data = line_dict[lineid]
                    line_id = codepattern.findall(line_data)
                    assert len(line_id) > 0
                    line_data = line_dict[line_id[0]]
                    item_pattern = re.compile(r'[(]#\d+[)]')
                    item_list = item_pattern.findall(line_data)
                    assert len(item_list) == 2
                    vertex1 = line_dict[item_list[0][1:-1]]
                    line_corr = vertex1.split("(")[1:]
                    coor = line_corr[1].split(')')[0]
                    coordinate = coor.split(',')[0:]
                    coordinate1 = np.array([float(s) for s in coordinate])

                    vertex2 = line_dict[item_list[1][1:-1]]
                    line_corr = vertex2.split("(")[1:]
                    coor = line_corr[1].split(')')[0]
                    coordinate = coor.split(',')[0:]
                    coordinate2 = np.array([float(s) for s in coordinate])

                    state=False
                    for v1 in vertex_list:
                        if np.linalg.norm(self.cache_points[k+'.'+v1]-coordinate1,2)<1e-3:
                            state=True
                            break
                    if not state:
                        coordinate1,coordinate2=coordinate2,coordinate1

                    line_normal = coordinate2 - coordinate1
                    self.cahce_normals[k+'.'+l1]=line_normal






if __name__ == '__main__':
    import time
    from OCC.Display.SimpleGui import init_display
    display, start_display, add_menu, add_function_to_menu = init_display("wx")

    # [[[1669.9099999993002, 724.912, -753.127], [1669.9099999993002, 724.912, -738.127]],
    #  [[1669.9099999993002, 724.912, -738.127], [1597.9099999993002, 724.912, -738.127]],
    #  [[1597.9099999993002, 724.912, -738.127], [1597.9099999993002, 724.912, -735.127]]]

    start = time.perf_counter()  # 起始时间
    name = '456'
    part = Part(name,part_dir=r'D:\工作\Deploying\do_design_automatic_assembly\new_json\05-11')
    display.DisplayShape(part.shape(),update=True)
    start_display()
    #print(part.get_normal('NL-07'))
    # end = time.perf_counter()  # 结束时间
    # print('运行时间%.10fs' % (end - start))
    #
    #
    # print("hello")
#    start_display()



